package cn.dansj.common.utils.redis.configure;

import cn.dansj.common.processor.meta.WriteToAutoConfiguration;
import cn.dansj.common.utils.redis.RedisProperties;
import cn.dansj.common.utils.redis.RedisUtils;
import cn.dansj.common.utils.redis.StringRedisTemplate;
import cn.dansj.common.utils.spring.context.condition.ConditionalOnClass;
import cn.dansj.common.utils.spring.context.condition.ConditionalOnProperty;
import io.lettuce.core.RedisURI;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.NettyCustomizer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@WriteToAutoConfiguration
@ConditionalOnProperty(prefix = "spring.redis", name = "host")
@ConditionalOnClass({LettuceConnectionFactory.class, GenericObjectPoolConfig.class, RedisURI.class})
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class DefaultRedisConfigure {
    public static final String redisPrefix = "spring.redis";
    private final static Logger logger = LoggerFactory.getLogger(DefaultRedisConfigure.class);

    @Bean
    @ConfigurationProperties(prefix = redisPrefix)
    public RedisProperties defaultRedisProperties() {
        logger.info("redisConfig init primaryRedisProperties");
        return new RedisProperties();
    }

    @Bean
    public StringRedisTemplate defaultRedisTemplate(RedisConnectionFactory defaultRedisConnectionFactory) {
        logger.info("redisConfig init stringRedisTemplate");
        return RedisUtils.createRedisTemplate(defaultRedisConnectionFactory);
    }

    @Bean(destroyMethod = "destroy")
    public LettuceConnectionFactory defaultRedisConnectionFactory(RedisProperties defaultRedisProperties) {
        logger.info("redisConfig init primaryRedisConnectionFactory");
        defaultRedisProperties.setClientName("primary");
        return (LettuceConnectionFactory) RedisUtils.getRedisConnectionFactory(defaultRedisProperties);
    }

    @Bean(name = "redisUtils")
    public RedisUtils redisUtils(StringRedisTemplate defaultRedisTemplate) {
        logger.info("redisConfig init redisUtils");
        return new RedisUtils(defaultRedisTemplate);
    }

    @Bean(destroyMethod = "shutdown")
    public ClientResources clientResources() {
        NettyCustomizer nettyCustomizer = new NettyCustomizer() {
            @Override
            public void afterChannelInitialized(Channel channel) {
                channel.pipeline().addLast(new IdleStateHandler(40, 0, 0));
                channel.pipeline().addLast(new ChannelDuplexHandler() {
                    @Override
                    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
                        if (evt instanceof IdleStateEvent) {
                            ctx.disconnect();
                        }
                    }
                });
            }
        };

        return ClientResources.builder().nettyCustomizer(nettyCustomizer).build();
    }
}
